package meshClipper;

import java.util.Vector;

import hEdge.HEFace;
import hEdge.HEGraph;
import hEdge.HENode;
import hEdge.HEdge;
import hdgeom.primitives.Rect;
import mmesh.MMesh;
import processing.core.PApplet;
import processing.core.PVector;
import processing.pdf.PGraphicsPDF;


public class MeshClipTest extends PApplet {
	MMesh mesh;
	float sX1 = -.1f;
	float sY1 = 0f;
	float sZ1 = -.3f;
	float sX2 = 0.5f;
	float sY2 = 0.3f;
	float sZ2 = 0.3f;
	
	int iC = 0;
	boolean[] corners = new boolean[8];
	PVector[] cornerPoints;
	String path="/Users/dillenburger_b/Desktop/";
	public void setup() {
		String file = path+"inho26bHigherTri.obj";
		mesh = new MMesh();
		mesh.loadOBJ(file);
		println(mesh.getBounds());
		println("loaded");
		// mesh.triangulateQuads();
		// println("triangulated");
		// mesh.saveObj("/Users/dillenburger_b/Desktop/inho26bHigherTri.obj");
		
		cornerPoints=new PVector[8];
		cornerPoints[0]=new PVector(sX1,sY1,sZ1);
		cornerPoints[1]=new PVector(sX2,sY1,sZ1);
		cornerPoints[2]=new PVector(sX2,sY2,sZ1);
		cornerPoints[3]=new PVector(sX1,sY2,sZ1);
		cornerPoints[4]=new PVector(sX1,sY1,sZ2);
		cornerPoints[5]=new PVector(sX2,sY1,sZ2);
		cornerPoints[6]=new PVector(sX2,sY2,sZ2);
		cornerPoints[7]=new PVector(sX1,sY2,sZ2);
	
		corners[0] = true;
		corners[3] = true;
		corners[4] = true;
		corners[7] = true;
		
		clip();
	}

	public void clip() {
		// zplanes
		int[] edges = mesh.clip(0, 0, sZ1, 0, 0, -1);
		println("nEdges"+edges.length);
		HEGraph graph = closeSide(edges, sX1, sY1, sX2, sY2);
		graph.translate(0, 0, sZ1);
		export(graph, path + "sideZ1" + timestamp() + ".obj");

		edges = mesh.clip(0, 0, sZ2, 0, 0, 1);
		graph = closeSide(edges, sX1, sY1, sX2, sY2);
		graph.translate(0, 0, sZ2);
		export(graph, path + "sideZ2" + timestamp() + ".obj");

		// xplanes
		mesh.XToZ();
		edges = mesh.clip(0, 0, sX1, 0, 0, -1);
		graph = closeSide(edges, sZ1, sY1, sZ2, sY2);
		graph.translate(0, 0, sX1);
		graph.XToZ();
		export(graph, path + "sideX1" + timestamp() + ".obj");

		edges = mesh.clip(0, 0, sX2, 0, 0, 1);
		graph = closeSide(edges, sZ1, sY1, sZ2, sY2);
		graph.translate(0, 0, sX2);
		graph.XToZ();
		export(graph, path + "sideX2" + timestamp() + ".obj");
		mesh.XToZ();

		// y planes
		mesh.YToZ();
		edges = mesh.clip(0, 0, sY1, 0, 0, -1);
		graph = closeSide(edges, sX1, sZ1, sX2, sZ2);
		graph.translate(0, 0, sY1);
		graph.YToZ();
		export(graph, path + "sideY1" + timestamp() + ".obj");

		edges = mesh.clip(0, 0, sY2, 0, 0, 1);
		graph = closeSide(edges, sX1, sZ1, sX2, sZ2);
		graph.translate(0, 0, sY2);
		graph.YToZ();
		export(graph, path + "sideY2" + timestamp() + ".obj");
		mesh.YToZ();

		println("clipped edges" + edges.length);
		mesh.saveObj(path + "clipped.obj");
	}
	public void export(HEGraph graph, String fileName){
		removeBorderFaces(graph);
		graph.exportOBJ(fileName);
	}

	public void removeBorderFaces(HEGraph graph) {
		Vector<HEFace> newFaces = new Vector<HEFace>();
		for (int j = 0; j < graph.heFaces.size(); j++) {
			HEFace f = graph.heFaces.get(j);
			boolean isBorder = false;
			HEdge hE = f.getHEdge();
			do {
				HENode n = hE.getOrg();
				for (int jjj = 0; jjj < corners.length; jjj++) {
					if (corners[jjj]) {
						if (n.dist(cornerPoints[jjj]) < 0.01f) {
							isBorder = true;
						}
					}
				}
				hE = hE.getNext();
			} while (hE != f.getHEdge());
			if (!isBorder) {
				newFaces.add(f);
			}
		}
		graph.heFaces = newFaces;
	}
	
	public HEGraph closeSide(int[] edges, float x1, float y1, float x2, float y2) {
		println("close Side start");
		iC++;
		// create side
		HEGraph heGraphZ1 = new HEGraph();
		Rect r = new Rect(x1, y1, x2, y2);
		for (int i = 0; i < edges.length; i += 2) {
			PVector n1 = mesh.getPoint(edges[i]);
			PVector n2 = mesh.getPoint(edges[i + 1]);
			if (r.contains(n1.x, n1.y)||r.contains(n2.x, n2.y)){
				heGraphZ1.addHEdge(n1.x, n1.y, n2.x, n2.y, 0.000001f);
			}
		}
		// bounds
		
		r.offset(-0.0001f);
		//offset to avoid online cases
		
		HENode n1 = heGraphZ1.addNode(r.x1, r.y1);
		HENode n2 = heGraphZ1.addNode(r.x2, r.y1);
		HENode n3 = heGraphZ1.addNode(r.x2, r.y2);
		HENode n4 = heGraphZ1.addNode(r.x1, r.y2);
		heGraphZ1.addHEdge(n1, n2);
		heGraphZ1.addHEdge(n2, n3);
		heGraphZ1.addHEdge(n3, n4);
		heGraphZ1.addHEdge(n4, n1);
		
		
		println("---------------start intersect");
		heGraphZ1.fuseCloseNodes2(0.0000001f);
		heGraphZ1.findduplicateEdges();
		heGraphZ1.findPointsOnSegments(0.00000001f);
		heGraphZ1.intersectPure();
		println("---------------intersected");
		
		r.offset(+0.002f);
		Vector<HEdge> newHedges = new Vector<HEdge>();
		for (int i = 0; i < heGraphZ1.hEdges.size(); i++) {
			HEdge hE = heGraphZ1.hEdges.get(i);
			hE.detach();
			if (r.contains(hE.x1(), hE.y1()) || r.contains(hE.x2(), hE.y2())) {
				newHedges.add(hE);
			}
		}
		for (int i = 0; i < newHedges.size(); i++) {
			HEdge hE = newHedges.get(i);
			hE.attach();
		}
		heGraphZ1.hEdges = newHedges;
		heGraphZ1.createHEFacesPur();
		println("faces created");
		heGraphZ1.removeEmptyNodes();
		heGraphZ1.rebuildIds();

		// display it
		PGraphicsPDF pdf = (PGraphicsPDF) createGraphics(width, height, PDF,
				"frame-####+" + iC + ".pdf");
		pdf.beginDraw();
		pdf.fill(255, 0, 0);
		// pdf.noFill();
		pdf.stroke(0);
		pdf.strokeWeight(0.0001f);
		pdf.translate(300, 300);
		pdf.scale(200);
		for (int i = 0; i < heGraphZ1.hEdges.size(); i++) {
			heGraphZ1.hEdges.get(i).display2D(pdf);
		}
		for (int i = 0; i < heGraphZ1.heFaces.size(); i++) {
			heGraphZ1.heFaces.get(i).display(pdf);
		}
		pdf.dispose();
		pdf.endDraw();

		println("close Side End");
		return heGraphZ1;
	}
	public static String timestamp(){
		return year() + nf( month(),2) +  nf( day(),2) + "-"  +  nf( hour(),2) +  nf( minute(),2) +   nf( second(),2);
	}

}
